"""
	doc: https://hotcoinex.github.io/zh/spot
"""
import base64
import hashlib
import hmac
from datetime import datetime
from ubroker import SpotBroker
from urllib.parse import urlparse, urlencode


class HotCoinSpot(SpotBroker):
	intervals = (60, 300, 900, 1800, 3600, 86400, 604800, 2592000)
	status = (
		SpotBroker.Created, SpotBroker.Submitted, SpotBroker.Partial, SpotBroker.Filled,
		SpotBroker.Revoking, SpotBroker.Canceled
	)
	
	def __init__(self, **kwargs):
		super().__init__('https://api.hotcoinfin.com', **kwargs)
	
	def order_format(self, order):
		return dict(
			id=order['id'], symbol=order['symbol'], side=order['type'],
			time=datetime.strptime(order['time'], '%Y-%m-%d %H:%M:%S').timestamp(), price=order['price'],
			quantity=order['count'], traded_quantity=float(order['count']) - float(order['leftcount']),
			state=self.status[order['statusCode']]
		)
	
	@staticmethod
	def trade_format(symbol, trade):
		return dict(
			id=trade['id'], time=trade['createdAt'], order_id=trade['orderId'], symbol=symbol, side=trade['type'],
			price=trade['price'], quantity=trade['filledAmount'],
			commission=trade['filledFees'], commission_asset='USDT'
		)
	
	def sign(self, method, path, **kwargs):
		params = dict(
			AccessKeyId=self.params['key'], SignatureMethod='HmacSHA256', SignatureVersion=2,
			Timestamp=datetime.utcnow().isoformat()[:-3] + 'Z', **kwargs
		)
		params = sorted(params.items(), key=lambda d: d[0], reverse=False)
		payload = '\n'.join([method, urlparse(self.uri).hostname, path, urlencode(params)])
		params = {k: v for k, v in params}
		params['Signature'] = base64.b64encode(
			hmac.new(self.params['secret'].encode('utf-8'), payload.encode('utf-8'), digestmod=hashlib.sha256).digest()
		).decode()
		return params
	
	async def basic(self):
		path = '/v1/common/symbols'
		response = await self.http_requests(SpotBroker.GET, path)
		return [dict(
			base=item['baseCurrency'].upper(), quote=item['quoteCurrency'].upper(), symbol=item['symbol'],
			price_tick=item['minOrderPrice'], min_quantity=item['minOrderCount'], min_notional=10
		) for item in response['data']]
	
	async def depth(self, symbol):
		path = '/v1/depth'
		response = await self.http_requests(SpotBroker.GET, path, params=dict(symbol=symbol))
		return response['data']['depth']
	
	async def kline(self, symbol, interval):
		path = '/v1/ticker'
		response = await self.http_requests(
			SpotBroker.GET, path, params=dict(
				symbol=symbol, step=self.intervals[SpotBroker.CandleIntervals.index(interval)]
			)
		)
		return response['data']
	
	async def trade(self, symbol):
		path = '/v1/trade'
		response = await self.http_requests(SpotBroker.GET, path, params=dict(symbol=symbol, count=20))
		today = datetime.today()
		return [dict(
			time=datetime.strptime(today.strftime('%Y-%m-%d') + item['time'], '%Y-%m-%d%H:%M:%S').timestamp() * 1000,
			side=SpotBroker.Buy if item['en_type'] == 'bid' else SpotBroker.Sell,
			price=float(item['price']), quantity=float(item['amount'])
		) for item in response['data']['trades']]
	
	async def ticker(self, symbol):
		path = '/v1/market/ticker'
		response = await self.http_requests(SpotBroker.GET, path, params=dict(symbol=symbol))
		for item in response['ticker']:
			if item['symbol'] == symbol:
				return dict(
					last=item['last'], low24h=item['low'],
					open24h=float(item['last']) - float(item['last']) * item['change'] / 100,
					high24h=item['high'], volume24h=item['vol']
				)
	
	async def balance(self):
		path = '/v1/balance'
		params = self.sign(SpotBroker.GET, path)
		response = await self.http_requests(SpotBroker.GET, path, params=params)
		return [dict(
			asset=item['asset'], frozen=item['frozen'], available=item['total']
		) for item in response['data']['wallet']]
	
	async def create_order(self, symbol, mold, side, quantity, line=None, direction=None, price=None):
		path = '/v1/order/place'
		params = self.sign(SpotBroker.POST, path, symbol=symbol, type=side, tradePrice=price, tradeAmount=quantity)
		response = await self.http_requests(SpotBroker.POST, path, params=params)
		return response['data']['ID']
	
	async def cancel_order(self, order_id, symbol):
		path = '/v1/order/cancel'
		params = self.sign(SpotBroker.POST, path, id=order_id)
		response = await self.http_requests(SpotBroker.POST, path, params=params)
		return response['code'] == 200
	
	async def order_detail(self, order_id, symbol):
		path = '/v1/order/detailById'
		params = self.sign(SpotBroker.GET, path, id=order_id)
		response = await self.http_requests(SpotBroker.GET, path, params=params)
		return self.order_format(response['data'])
	
	async def active_orders(self, symbol):
		path = '/v1/order/entrust'
		params = self.sign(SpotBroker.GET, path, symbol=symbol, type=1, page=1, page_size=100)
		response = await self.http_requests(SpotBroker.GET, path, params=params)
		return [self.order_format(order) for order in response['data']['entrutsCur']]
	
	async def history_orders(self, symbol, start, end):
		path = '/v1/order/entrust'
		params = self.sign(SpotBroker.GET, path, symbol=symbol, type=2, page=1, page_size=100)
		response = await self.http_requests(SpotBroker.GET, path, params=params)
		return [self.order_format(order) for order in response['data']['entrutsHis']]
	
	async def history_trades(self, symbol, start, end):
		path = '/v1/order/matchresults'
		params = self.sign(SpotBroker.GET, path, symbol=symbol)
		response = await self.http_requests(SpotBroker.GET, path, params=params)
		return [self.trade_format(symbol, trade) for trade in response['data']['entrutsHis']]
